local Class = require('lua.lang.Class')
local LuaValue = require('lua.vm.LuaValue')
local LuaNumber = require('lua.vm.LuaNumber')

--- @class LuaString : LuaValue
--- @field v string
local LuaString = Class {
	__extends = LuaValue
}

--- @constructor
--- @param v string
--- @return LuaString
function LuaString:new(v)
	--- @type LuaString
	local obj = {
		v = v
	}
	return setmetatable(obj, LuaString)
end

--- @param bytes number[]
--- @param off number
--- @param len number
--- @return LuaString
function LuaString:valueUsing(bytes, off, len)
	return self:valueOf(string.char(table.unpack(bytes, off, off + len - 1)))
end

--- @return number
function LuaString:type()
	return self.TYPE_STRING
end

--- @return string
function LuaString:typeName()
	return self.TYPE_NAMES[self:type() + 1]
end

--- @return string
function LuaString:toLString()
	return self.v
end

--- @param s string
--- @return LuaString
function LuaString:valueOf(s)
	return LuaString:new(s)
end

--- @param value LuaValue
--- @return boolean
function LuaString:eq_b(value)
	return value:rawEq(self)
end

--- @param s LuaString
--- @return boolean
function LuaString:rawEq(s)
	local status, ret = pcall(function()
		return self.v == s.v
	end)
	return status and ret
end

--- @return boolean
function LuaString:isNumber()
	local n = tonumber(self.v)
	return n ~= nil
end

--- @return number
function LuaString:toNumber()
	return tonumber(self.v)
end

--- @return LuaNumber
function LuaString:toLuaNumber()
	return self:isNumber() and LuaNumber:valueOf(self:toNumber()) or LuaNumber.ZERO
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:add(rhs)
	return rhs:add(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:sub(rhs)
	return rhs:sub(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:mul(rhs)
	return rhs:mul(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:div(rhs)
	return rhs:div(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:mod(rhs)
	return rhs:mod(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:pow(rhs)
	return rhs:pow(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:iDiv(rhs)
	return rhs:iDiv(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:bAnd(rhs)
	return rhs:bAnd(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:bOr(rhs)
	return rhs:bOr(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:bXor(rhs)
	return rhs:bXor(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:shl(rhs)
	return rhs:shl(self)
end

--- @param rhs LuaValue
--- @return LuaValue
function LuaString:shr(rhs)
	return rhs:shl(self)
end

--- @return LuaValue
function LuaString:bNot()
	return self:isNumber() and self:toLuaNumber():bNot() or LuaValue:bNot()
end

--- @return LuaValue
function LuaString:neg()
	return self:isNumber() and self:toLuaNumber():neg() or LuaValue:neg()
end

--- @return LuaValue
function LuaString:len()
	return LuaNumber:valueOf(#self.v)
end

--- @return boolean
function LuaString:isString()
	return true
end

return LuaString